#define N 100
#include <stdio.h>
#include <omp.h>

void p_vvxv(int *v1, int *v2, int *v3, int n);
void t_vvxv(int *v1, int *v2, int *v3, int n);

#pragma omp declare variant(p_vvxv) match(construct={parallel})
#pragma omp declare variant(t_vvxv) match(construct={target})
void vvxv(int *v1, int *v2, int *v3, int n) // base function
{
    for (int i = 0; i < n; i++) 
        v3[i] = v1[i] * v2[i];
}

void p_vvxv(int *v1, int *v2, int *v3, int n) // function variant
{
    #pragma omp for
    for (int i = 0; i < n; i++) 
        v3[i] = v1[i] * v2[i] * 3;
}

#pragma omp begin declare target
void t_vvxv(int *v1, int *v2, int *v3, int n) // function variant
{
    #pragma omp distribute simd
    for (int i = 0; i < n; i++) 
        v3[i] = v1[i] * v2[i] * 2;
}
#pragma omp end declare target

int main()
{
    int v1[N], v2[N], v3[N];
    for (int i = 0; i < N; i++) {
        v1[i] = i + 1;
        v2[i] = -(i + 1);
        v3[i] = 0;
    }

    #pragma omp parallel
    {
        vvxv(v1, v2, v3, N);
    }
printf(" %d  %d\n", v3[0], v3[N-1]);  // from p_vvxv -- output: -3  -30000

    #pragma omp target teams map(to: v1[:N], v2[:N]) map(from: v3[:N])
    {
        vvxv(v1, v2, v3, N);
    }
    printf(" %d  %d\n", v3[0], v3[N-1]);  // from t_vvxv -- output: -2  -20000

    vvxv(v1, v2, v3, N);
    printf(" %d  %d\n", v3[0], v3[N-1]);  // from vvxv (base) -- output: -1  -10000

    return 0;
   }
